package client;

/**
 *
 * @author pquiring
 */

import java.io.*;
import java.net.*;
import java.util.*;
import javax.net.ssl.*;

import javaforce.*;

public class Client extends javax.swing.JFrame {

  /**
   * Creates new form Client
   */
  public Client() {
    initComponents();
    JFImage img = new JFImage();
    img.load(getClass().getResourceAsStream("/jfrdp.png"));
    setIconImage(img.getImage());
    JFAWT.centerWindow(this);
    readConfig();
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    jLabel1 = new javax.swing.JLabel();
    jLabel2 = new javax.swing.JLabel();
    webPassword = new javax.swing.JPasswordField();
    host = new javax.swing.JTextField();
    connect = new javax.swing.JButton();
    error = new javax.swing.JLabel();
    jLabel3 = new javax.swing.JLabel();
    rdpPassword = new javax.swing.JPasswordField();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("jfRDP Client");

    jLabel1.setText("Host:");

    jLabel2.setText("Web Password:");

    connect.setText("Connect");
    connect.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        connectActionPerformed(evt);
      }
    });

    jLabel3.setText("RDP Password:");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(layout.createSequentialGroup()
            .addGap(0, 0, Short.MAX_VALUE)
            .addComponent(connect))
          .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(jLabel2)
              .addComponent(jLabel1)
              .addComponent(jLabel3))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(rdpPassword)
              .addComponent(webPassword, javax.swing.GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE)
              .addComponent(host)))
          .addComponent(error, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addContainerGap())
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(jLabel1)
          .addComponent(host, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addGap(18, 18, 18)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(jLabel2)
          .addComponent(webPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(jLabel3)
          .addComponent(rdpPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(error, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(connect)
        .addContainerGap())
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

  private void connectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectActionPerformed
    writeConfig();
    connect();
  }//GEN-LAST:event_connectActionPerformed

  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) {
    JF.initHttps();
    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        new Client().setVisible(true);
      }
    });
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton connect;
  private javax.swing.JLabel error;
  private javax.swing.JTextField host;
  private javax.swing.JLabel jLabel1;
  private javax.swing.JLabel jLabel2;
  private javax.swing.JLabel jLabel3;
  private javax.swing.JPasswordField rdpPassword;
  private javax.swing.JPasswordField webPassword;
  // End of variables declaration//GEN-END:variables

  private String encodePassword() {
    String pass = new String(webPassword.getPassword());
    String u_p = ":" + pass;
    String base64_u_p = new String(javaforce.Base64.encode(u_p.getBytes()));
    return base64_u_p;
  }

  private void connect() {
    host.setEnabled(false);
    connect.setEnabled(false);
    webPassword.setEnabled(false);
    rdpPassword.setEnabled(false);
    new Thread() {
      public void run() {
        connect2();
      }
    }.start();
  }

  private String errmsg;

  private void connect2() {
    errmsg = null;
    String xml = connect_raw();
    if (xml == null || xml.length() == 0) {
      if (errmsg == null) errmsg = "Connection Failed";
      java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
          JFAWT.showError("Error", errmsg);
          host.setEnabled(true);
          connect.setEnabled(true);
          webPassword.setEnabled(true);
          rdpPassword.setEnabled(true);
        }
      });
      return;
    }
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        dispose();
      }
    });
    WDS.startClient(xml, "Viewer", new String(rdpPassword.getPassword()));
  }

  /** Connect using SSLSocket */
  private String connect_raw() {
    String server = host.getText();
    try {
      int port = 33001;
      int idx = server.indexOf(":");
      if (idx != -1) {
        server = server.substring(0, idx);
        port = Integer.valueOf(server.substring(idx+1));
      }
      TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
          }
          public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
          public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
        }
      };
      // Let us create the factory where we can set some parameters for the connection
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      SSLSocketFactory sslsocketfactory = (SSLSocketFactory) sc.getSocketFactory();  //this method will work with untrusted certs
      Socket s = sslsocketfactory.createSocket(server, port);
      s.setSoTimeout(10 * 1000);

      StringBuilder sb = new StringBuilder();
      sb.append("GET /invite HTTP/1.0\r\n");
      sb.append("Host: " + server + "\r\n");
      sb.append("Authorization: Basic " + encodePassword() + "\r\n");
      sb.append("\r\n");

      OutputStream os = s.getOutputStream();
      InputStream is = s.getInputStream();
      os.write(sb.toString().getBytes());
      sb = new StringBuilder();
      byte buf[] = new byte[1024];
      String xml = null;
      while (s.isConnected() || is.available() > 0) {
        int read = is.read(buf);
        if (read == -1) break;
        if (read > 0) {
          sb.append(new String(buf, 0, read));

          String response = sb.toString();
          idx = response.indexOf("\r\n\r\n");
          if (idx == -1) continue;
          String headers[] = response.substring(0, idx).split("\r\n");
          idx += 4;
          xml = response.substring(idx);
          int length = -1;
          for(int a=0;a<headers.length;a++) {
            if (headers[a].startsWith("Content-Length:")) {
              length = Integer.valueOf(headers[a].substring(16));
              break;
            }
          }
          if (xml.length() < length) {
            xml = null;
            continue;
          }
          break;

        }
      }
      s.close();
      return xml;
    } catch (Exception e) {
      e.printStackTrace();
      errmsg = e.toString();
      return null;
    }
  }

  /** Connect using URLConnection : Hangs too often. */
  private String connect_url() {
    error.setText("");
    try {
      String server = host.getText();
      if (server.indexOf(":") == -1) {
        server = server + ":33001";
      }
      URL url = new URL("https://" + server + "/invite");
      URLConnection conn = url.openConnection();
      conn.addRequestProperty("Authorization", "Basic " + encodePassword());
      //conn.setAllowUserInteraction(true);
      conn.connect();
      String xml = null;
      if (true) {
        InputStream is = conn.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte buf[] = new byte[1024];
        while (true) {
          int read = is.read(buf);
          if (read == -1) break;
          if (read > 0) {
            baos.write(buf, 0, read);
          }
        }
        xml = new String(baos.toByteArray());
      } else {
        xml = (String)conn.getContent();
      }
      return xml;
    } catch (Exception e) {
      e.printStackTrace();
      error.setText(e.toString());
      return null;
    }
  }

  public void readConfig() {
    try {
      Properties p = new Properties();
      FileInputStream fis = new FileInputStream(JF.getUserPath() + "/.jfrdp-client.cfg");
      p.load(fis);
      fis.close();
      String lastHost = p.getProperty("lastHost");
      if (lastHost != null) {
        host.setText(lastHost);
      }
    } catch (Exception e) {
      JFLog.log(e);
    }
  }

  public void writeConfig() {
    try {
      Properties p = new Properties();
      p.setProperty("lastHost", host.getText());
      FileOutputStream fos = new FileOutputStream(JF.getUserPath() + "/.jfrdp-client.cfg");
      p.store(fos, "#jfRDP-client");
      fos.close();
    } catch (Exception e) {
      JFLog.log(e);
    }
  }
}
